package com.muchfish.algorithm.linkedlist;

import com.muchfish.algorithm.linkedlist.pojo.ListNode;

/**
 * <a href="https://leetcode.cn/problems/reverse-nodes-in-k-group/description/">题目：25. K个一组翻转链表</a>
 * <br>
 * 题目描述：<br>
 * 给你链表的头节点 head ，每 k 个节点一组进行翻转，请你返回修改后的链表。<br>
 * k 是一个正整数，它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍，那么请将最后剩余的节点保持原有顺序。<br>
 * 你不能只是单纯的改变节点内部的值，而是需要实际进行节点交换。<br>
 * <br>
 * 示例1：<br>
 * <img src="https://assets.leetcode.com/uploads/2020/10/03/reverse_ex1.jpg"><br>
 * 示例2：<br>
 * <img src="https://assets.leetcode.com/uploads/2020/10/03/reverse_ex2.jpg"><br>
 * 解题思路： <br>
 * 方法一：模拟<br>
 * 1. 先判断链表是否为空，以及链表长度是否大于等于k，若不满足条件则直接返回原链表。<br>
 * 2. 遍历链表，记录链表长度，并判断是否能够整除k，若不能整除，则返回原链表。<br>
 * 3. 翻转链表，并返回翻转后的链表。<br>
 * 细节补充：<br>
 * 除了翻转其本身之外，还需要将子链表的头部与上一个子链表连接，以及子链表的尾部与下一个子链表连接<br>
 *
 * <br>
 */
public class LinkedList6 {
    public static void main(String[] args) {
        ListNode head = new ListNode(1);
        head.next = new ListNode(2);
        head.next.next = new ListNode(3);
        head.next.next.next = new ListNode(4);
        ListNode listNode = new LinkedList6().reverseKGroup(head, 2);

    }
    public ListNode reverseKGroup(ListNode head, int k) {
        ListNode hair = new ListNode(0);
        hair.next = head;
        ListNode pre = hair;

        while (head != null) {
            ListNode tail = pre;
            // 查看剩余部分长度是否大于等于 k
            for (int i = 0; i < k; ++i) {
                tail = tail.next;
                if (tail == null) {
                    return hair.next;
                }
            }
            ListNode nex = tail.next;
            ListNode[] reverse = myReverse(head, tail);
            head = reverse[0];
            tail = reverse[1];
            // 把子链表重新接回原链表
            pre.next = head;
            tail.next = nex;
            pre = tail;
            head = tail.next;
        }

        return hair.next;
    }

    public ListNode[] myReverse(ListNode head, ListNode tail) {
        // 反转链表
        // p：当前节点 prev：前驱节点 初始时，prev 指向 tail.next
        //ListNode prev = null; 指向null也行(推荐指向null，好理解)。prev 指向 tail.next 的效果会在该方法执行完后再处理了一遍
        ListNode prev = tail.next;
        ListNode p = head;
        while (prev != tail) {
            ListNode nex = p.next;
            p.next = prev;
            prev = p;
            p = nex;
        }
        return new ListNode[]{tail, head};
    }
}
